package com.smsc.headend.task.engine.handler.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.common.enums.PaymentSwithPreToPostOptGroupEnum;
import com.smsc.headend.common.enums.TemplateType;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.UDateUtils;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.ansi.AnsiData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.report.entity.LogDeviceParamResult;
import com.smsc.headend.module.report.entity.LogDeviceParamResultSub;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.SubTaskStatus;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.utils.AnsiUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;


@Slf4j
public class ReadProfilePeriodHandler implements TaskHandler {
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    TaskDAO taskDAO;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        if (!(deviceData instanceof CosemData) && !(deviceData instanceof AnsiData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }

        Integer periodInDevice;
        if (deviceData instanceof AnsiData) {
            AnsiData ansiData = (AnsiData) deviceData;
            periodInDevice = (int) ansiData.getAnsiByteBuffer().getUInt8(8) * 60;
        } else {
            CosemData cosemData = (CosemData) deviceData;
            String periodValue = cosemData.getValue();
            String type = cosemData.getType();
            periodInDevice = Convert.toInt(cosemXmlService.getData(type, periodValue));
        }
        Map<String, Object> param = getParameterMap(task, atomicTask);
        Long lpTemplateId = Long.valueOf(String.valueOf(param.get("lpTemplateId")));
        Long lpGroupTemplateId = Long.valueOf(String.valueOf(param.get("groupTemplateId")));
        Long lpDataItemId = Long.valueOf(String.valueOf(param.get("lpDataItemId")));
//        Integer periodInDB = assetManagementService.getProfileIntervalTime(task.getMeterId(), lpTemplateId);
        String periodType = assetManagementService.getProfileIntervalType(lpTemplateId);
        String convertValue = UDateUtils.getConvertPeriodByType(Convert.toInt(periodInDevice), periodType);
//        if (periodInDevice.intValue() != periodInDB.intValue()) {
//            log.error("{} device ,{} in udis", periodInDevice, periodInDB);
//            throw new UDISTaskHandlerException(TaskHandlerErrorCode.PROFILE_PERIOD_MISMATCH.getErrorCode());
//        }
        log.info("Period CosemData Value {}, intervalType {},convertValue {}", periodInDevice, periodType, convertValue);
        Integer src = LogDeviceParamResult.Src.MANUAL.getCode();
        if (StrUtil.equalsIgnoreCase(TaskType.ScheduleGet_LP_Period_OBJS.name(), task.getTaskType())) {
            src = LogDeviceParamResult.Src.SCH.getCode();
        }
        assetManagementService.saveDeviceParamResultReport(task.getMeterId(), DeviceType.METER.getId(), src, lpGroupTemplateId, TemplateType.LOAD_PROFILE.getId(), lpDataItemId, task.getTaskNo(), LogDeviceParamResultSub.ParamName.LP_PRD.getName(), convertValue, "");

        Map<String, String> result = MapUtil.newHashMap();
        result.put("periodType", periodType);
        result.put("lpTemplateId", lpTemplateId.toString());
        result.put("value", convertValue);
        if (StrUtil.equalsIgnoreCase(task.getTaskType(), TaskType.Action_DeviceParamConfig_Get.name())) {
            OperationName operationName = OperationName.forId(atomicTask.getOperationId());
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), result, 600L, true);
            if (isSubTaskGroupLastAtomicTask(task, atomicTask)) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), "subTaskCompleted", true, 600L, true);
            }
        }

        return 1;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        if (StrUtil.equalsIgnoreCase(task.getTaskType(), TaskType.Action_DeviceParamConfig_Get.name())) {
            OperationName operationName = OperationName.forId(atomicTask.getOperationId());
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), message, 600L, false);
        }
        if (StrUtil.equalsIgnoreCase(task.getTaskType(), TaskType.SwitchMeterPaymentPreToPost.name())) {
            Map<String, Object> parameterMap = getParameterMap(task, atomicTask);
            Long taskId = MapUtil.getLong(parameterMap, "taskId");
            assetManagementService.updateStepStatusToPost(taskId,task.getTaskNo(), task.getMeterId(), PaymentSwithPreToPostOptGroupEnum.ON_DEMAND_MONTHLY_BILLING_PROFILE.getOperationGroup().longValue(), SubTaskStatus.Failed.getCode(), null, SystemClock.now() / 1000,
                    String.format("handle %s fail, [%s]", OperationName.forId(atomicTask.getOperationId()).getName(), message), false);
        }
        return -1;
    }
}
